#include <sys/shm.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <errno.h> 
#include <string.h> 
#include <stdarg.h> 
#include <stdint.h> 
#include <stddef.h> 
#include <unistd.h> 
#include "shm_segment.h" 

static void my_print(const char * format, ...) {
    char buff[8192] = "\0";

    va_list args;
    va_start(args, format);
    vsnprintf(buff, sizeof(buff), format, args);
    va_end(args);

    buff[sizeof(buff) - 1] = 0;

    printf("%s",buff);
}

int shm_segment::__create(key_t key, size_t size) {
    printf("%s key:%d ch:%c\n", __func__, key, this->ch);

    int ret = shmget(key, size, 0666 | IPC_CREAT | IPC_EXCL);
    if (ret != -1) {
        this->base_addr = shmat(ret, nullptr, 0);
        if (reinterpret_cast<intptr_t>(this->base_addr) == -1) {
            printf("shmat error<%s>.\n", strerror(errno));
            return -1;
        }

        this->shmid = ret;
        return 0;
    }

    if (errno != EEXIST) {
        printf("shmget key<%d> error<%s>.\n", key, strerror(errno));
        return -1;
    }
    
    ret = shmget(key, 0, 0666);
    if (ret == -1) {
        printf("shmget key<%d> error<%s>.\n", key, strerror(errno));
        return -1;
    }

    ret = shmctl(ret, IPC_RMID, nullptr);
    if (ret < 0) {
        printf("rm shm_key<%d> error<%s>.\n", key, strerror(errno));
        return -1;
    }

    ret = shmget(key, size, 0666 | IPC_CREAT | IPC_EXCL);
    if (ret == -1) {
        printf("shmget key<%d> error<%s>.\n", key, strerror(errno));
        return -1;
    }

    this->base_addr = shmat(ret, nullptr, 0);
    if (reinterpret_cast<intptr_t>(this->base_addr) == -1) {
        printf("shmat error<%s>.\n", strerror(errno));
        shmctl(ret, IPC_RMID, nullptr);
        return -1;
    }

    this->shmid = ret;
    return 0;
}

int shm_segment::__attach(key_t key) {
    printf("%s key:%d ch:%c\n", __func__, key, this->ch);

    int ret = shmget(key, 0, 0666);
    if (ret == -1) {
        printf("shmget key<%d> error<%s>.\n", key, strerror(errno));
        return -1;
    }

    this->base_addr = shmat(ret, nullptr, 0);
    if (reinterpret_cast<intptr_t>(this->base_addr) == -1) {
        printf("shmat error<%s>.\n", strerror(errno));
        return -1;
    }

    this->shmid = ret;
    return 0;
}

void shm_segment::fini() {
    if (this->base_addr != nullptr) {
        if (shmdt(this->base_addr) == -1) {
            printf("shmdt error<%s>\n", strerror(errno));
        }
        this->base_addr = nullptr;
    }

    if (this->shmid != -1) {
        if (shmctl(this->shmid, IPC_RMID, nullptr) == -1) {
            printf("pid:%d rm shmid<%d> error<%s>.\n", getpid(), this->shmid, strerror(errno));
            return;
        }
    }
    
    this->shmid = -1;
    printf("id:%d fini\n", getpid());
}
